package screen;

import procedure.Find;
import procedure.Node;
import procedure.Show;
import procedure.TestProcess;

import java.util.*;

/**
 * 矩阵
 * Created by sk.z on 2022/3/3.
 */
public class Matrix {

    private int high;
    private int length;
    private Block[][] matrix;
    private List<LitNode> litNodeList;

    public static void main(String[] args) {
        Matrix m = new Matrix(TestProcess.B());
        m.print();
    }

    public Matrix(Node process) {
        List<List<Node>> lineList = Find.travelGetAllSingleLine(process);

        litNodeList = new ArrayList<>();
        //Node -> LitNode
        Map<Node, LitNode> nodeMapLit = new HashMap<>();
        for (List<Node> line : lineList) {
            for (Node n : line) {
                if (nodeMapLit.containsKey(n)) {
                    continue;
                }
                LitNode lit = new LitNode(n);
                nodeMapLit.put(n, lit);
                litNodeList.add(lit);
            }
        }

        //计算litNode出现个数 最深深度 赋下级关系
        for (List<Node> line : lineList) {
            for (int d = 0; d < line.size(); d++) {
                Node n = line.get(d);
                LitNode lit = nodeMapLit.get(n);
                lit.num++;
                lit.deepest = Math.max(lit.deepest, d);
                if (lit.nextList.isEmpty() && n.getAfterList().size() > 0) {
                    for (Node after : n.getAfterList()) {
                        lit.nextList.add(nodeMapLit.get(after));
                    }
                }
            }
        }

        //计算高宽
        high = lineList.size();
        length = lineList.stream().mapToInt(List::size).max().orElse(0);

        //初始化阵列
        matrix = new Block[high][length];
        for (int h = 0; h < high; h++) {
            for (int l = 0; l < length; l++) {
                matrix[h][l] = new Block(h, l);
            }
        }

        for (int h = 0; h < lineList.size(); h++) {
            List<Node> line = lineList.get(h);
            for (int l = 0; l < line.size(); l++) {
                matrix[h][l].litNode = nodeMapLit.get(line.get(l));
            }
        }
    }

    public void print() {
        align();
        sink();
        show();
    }

    private void show() {
        for (int h = 0; h < high; h++) {
            for (int l = 0; l < length; l++) {
                Block b = matrix[h][l];
                if (Objects.nonNull(b)) {
                    System.out.print(b.bracketName());
                }
            }
            System.out.println();
        }
    }

    //对齐
    private void align() {
        LitNode litNode;
        while (Objects.nonNull(litNode = alignFindDeepestNode())) {
            if (litNode.num <= 1) {
                litNode.isAlign = true;
                continue;
            }

            //迁移对齐
            for (int h = 0; h < high; h++) {
                Block block = findBlockByLitNode(litNode, h);
                if (Objects.isNull(block)) {
                    continue;
                }
                block.litNode = null;
                getBlockByXY(h, litNode.deepest).litNode = litNode;
            }
            litNode.isAlign = true;
        }
    }

    //下沉相同节点
    private void sink() {
        for (int x = 0; x < high; x++) {
            for (int y = 0; y < length; y++) {
                Block curBlock = matrix[x][y];
                if (Objects.isNull(curBlock.litNode)){
                    continue;
                }
                for (int next = x + 1; next < high; next++) {
                    Block nextBlock = matrix[next][y];
                    if (Objects.isNull(nextBlock)){
                        break;
                    }
                    if (curBlock.litNode==nextBlock.litNode){
                        curBlock.litNode.num--;
                        curBlock.litNode=null;
                        curBlock = nextBlock;
                    }
                }
            }
        }
    }

    private LitNode alignFindDeepestNode() {
        LitNode deepestNode = null;
        for (LitNode n : litNodeList) {
            if (n.isAlign) {
                continue;
            }
            if (Objects.isNull(deepestNode)) {
                deepestNode = n;
            } else if (deepestNode.deepest < n.deepest) {
                deepestNode = n;
            }
        }
        return deepestNode;
    }

    private Block findBlockByLitNode(LitNode litNode, int h) {
        for (Block b : matrix[h]) {
            if (Objects.nonNull(b.litNode) && b.litNode == litNode) {
                return b;
            }
        }
        return null;
    }

    private Block getBlockByXY(int x, int y) {
        return matrix[x][y];
    }

}
